23.07.20
오늘 한 일
- Gloddy 개발 - 게시글 작성 페이지 구현
- CS 스터디 진행
하루 요약
- 13:30 ~ 18:00 / 19:00 ~ 21:00 카공
Gloddy 개발 - 게시글 작성 페이지 구현
저번 전역 상태에 대한 고민을 해보고, 전역 상태를 사용하지 않고 특정 범위에 국한된 상태는 그 범위 내에서 관리하기 위해 Provider
로 묶어서 관리해보기로 했다.
일단 최종 구현은 다음과 같다.

TopNavigationBar
에서 이미지 추가 버튼이 존재한다.
Page
컴포넌트에서는 다음과 같이 구성된다.
<main>
<WriteTopNavigationBar />
<InputForm />
</main>
InputForm
컴포넌트에 TNB를 넣는다 ❌- InputForm은 form 만 들고 있어야 함
- page 컴포넌트에서 상태를 관리하고, InputForm에 props로 넘겨준다 ❌
- page 컴포넌트는 서버 컴포넌트이기 때문에 상태를 가질 수 없다. (페이지 컴포넌트는 RSC로 하자고 컨벤션 맞춤)
- Context API를 사용해서 상태를 공유한다 🤔
- 전역 상태 라이브러리를 사용해서 상태를 공유한다 🤔
전역 상태
라고 보기엔 애매하다. 게시글 작성 페이지
에서만 사용하기 때문에 특정 범위에 국한된 상태
라고 보는게 맞다.
그래서 Context API
를 사용해서 상태를 공유하기로 했다.
Context API 사용
export default function WritePage() {
return (
<main>
<WriteContextProvider>
<WriteTopNavigationBar />
<InputForm />
</WriteContextProvider>
</main>
);
}
WriteContextProvider
컴포넌트를 만들어보았다.
// WriteContext.tsx
'use client';
import { createContext, useContext, useMemo, useState } from 'react';
import type { ImageType, StrictPropsWithChildren } from '@/types';
type WriteContextType = {
images: ImageType[];
setImages: React.Dispatch<React.SetStateAction<ImageType[]>>;
};
const WriteContext = createContext<WriteContextType | null>(null);
function WriteContextProvider({ children }: StrictPropsWithChildren) {
const [images, setImages] = useState<ImageType[]>([]);
const contextValue = useMemo(() => ({ images, setImages }), [images]);
return <WriteContext.Provider value={contextValue}>{children}</WriteContext.Provider>;
}
function useWriteContext() {
const context = useContext(WriteContext);
if (context === null) {
throw new Error('useWriteContext must be used within a WriteContextProvider');
}
return context;
}
export { useWriteContext, WriteContextProvider };
뭔가 복잡해 보이지만 사실 별거 없다.
- 먼저
WriteContext
를 만들어준다. WriteContextProvider
컴포넌트를 만들어준다.WriteContext
의value
로images
와setImages
를 넘겨준다.- 이 때,
contextValue
는 useMemo를 사용해서 최적화를 해준다.
useWriteContext
를 만들어준다.WriteContext
를 사용할 때,useContext
를 사용해서context
를 가져온다.- 만약
context
가null
이라면,useWriteContext
를 사용한 컴포넌트가WriteContextProvider
컴포넌트 내부에 존재하지 않는다는 것이다. - 그래서 에러를 던져준다.
context
가null
이 아니라면,context
를 반환해준다.
만약 위에서 3번 처리를 해주지 않는다면(타입을 좁혀주지 않는다면), context를 사용할 때 타입스크립트에서 null
일 수도 있다고 생각하기 때문에 null
체크를 해줘야한다.
context 사용
const { images, setImages } = useWriteContext();
이렇게 사용하고 싶은 곳에서 useWriteContext
를 사용해서 images
와 setImages
를 가져온다.
하지만, Provider로 감싸진 곳에 선언된 컴포넌트에서만 사용할 수 있다.
이렇게 지역적으로 사용할 수 있는 상태를 만들어줄 수 있다.
만약 전역 상태 라이브러리를 사용했다면?
전역 상태 라이브러리를 사용했더라도 동일하게 로직을 구현할 수 있었을 것이다.
하지만, 다른 곳에서도 해당 상태를 사용할 수 있기 때문에, 전역으로 상태를 빼는 건 조심스럽게 결정해야 한다고 생각한다.
위 처럼 상태를 사용할 수 있는 범위를 정해서 사용하는게 더 좋은 것 같다.
Jotai도 비슷한 생각을 했다
Jotai
의 컨셉 문서를 읽어보면 Context의 리렌더링 문제에서 출발한 것 같다.
이 라이브러리가 나오기 전 use-context-selector로 문제를 해결하려고 했었다.
그리고 Jotai의 전신인 use-atom도 있었다.
Jotai에서 Provider
라는 것도 제공해준다.
The Provider component is to provide state for a component sub tree. Multiple Providers can be used for multiple subtrees, and they can even be nested. This works just like React Context.
If an atom is used in a tree without a Provider, it will use the default state. This is so-called provider-less mode.
Providers are useful for three reasons:
- To provide a different state for each sub tree.
- To accept initial values of atoms.
- To clear all atoms by remounting.
선택적으로 store
를 사용해서 특정 범위 내에서 상태를 관리할 수 있다.
상황에 따라 전역 상태로도, 특정 범위 내에서만 상태를 관리할 수도 있다.
... 다음에 기회가 되면 한 번 써봐야겠다.
내일 할 일
- Gloddy 상호평가 페이지 구현
- Rust 공부
- GDG 회의 8시